<template>
  <div style="width: 100%">
    <file-upload-local
      v-if="provider === 'local'"
      v-model="fileList"
      :accept="acceptType"
      :tips="tips"
      :limit="limit"
      :compress="compress"
      :list-type="listType"
      @select="fileSelected"
    />
    <file-upload-cos
      v-if="provider === 'qcloud'"
      v-model="fileList"
      :accept="acceptType"
      :tips="tips"
      :limit="limit"
      :compress="compress"
      :list-type="listType"
      :auto-upload="autoUpload"
      @select="fileSelected"
    />
  </div>
</template>

<script lang="ts" setup>
  import type { UploadFile, UploadRawFile } from 'element-plus'
  import FileUploadLocal from './local.vue'
  import FileUploadCos from './cos.vue'
  import { fileLists } from '@/types/competition'

  // 定义 props 类型
  interface Props {
    modelValue?: string | fileLists[]
    accept?: string
    tips?: string
    listType?: 'text' | 'picture' | 'picture-card'
    compress?: number
    limit?: number
    provider?: string
    autoUpload?: boolean
  }

  // 定义 emits 类型
  interface Emits {
    (e: 'update:modelValue', value: string | fileLists[]): void
    (e: 'select', file: UploadRawFile | UploadFile): void
  }

  // Props 定义
  const props = withDefaults(defineProps<Props>(), {
    modelValue: undefined,
    accept: '*',
    tips: undefined,
    listType: 'text',
    compress: 0,
    limit: 1,
    provider: 'local',
    autoUpload: true,
  })

  // Emits 定义
  const emit = defineEmits<Emits>()

  // 响应式数据
  const acceptType = ref<string>('')
  const fileList = ref<UploadFile[]>([])
  const isUpdatingFromProps = ref<boolean>(false) // 防止递归更新的标志位

  // 兼容大小写格式
  const fillAccept = () => {
    if (!props.accept || props.accept === '*') {
      acceptType.value = '*'
      return
    }
    acceptType.value = props.accept
  }

  // 填充数据
  const fillValue = (val: string | fileLists[] | undefined) => {
    isUpdatingFromProps.value = true // 设置标志位
    if (!props.limit || props.limit === 1) {
      // 单文件模式
      if (typeof val === 'string' && val) {
        fileList.value = [
          {
            url: val,
            name: val,
            uid: Date.now(),
            status: 'success' as const,
          },
        ]
      } else {
        fileList.value = []
      }
    } else {
      // 多文件模式
      if (Array.isArray(val)) {
        fileList.value = val.map((item) => {
          if (typeof item === 'object' && 'uid' in item && 'status' in item) {
            return item as UploadFile
          } else {
            // 转换 fileLists 到 UploadFile
            const fileItem = item as fileLists
            return {
              url: fileItem.url || '',
              name: fileItem.name || '',
              uid: Date.now() + Math.random(),
              status: 'success' as const,
            }
          }
        })
      } else {
        fileList.value = []
      }
    }
    fillAccept()
    // 使用 nextTick 确保 DOM 更新后再重置标志位
    nextTick(() => {
      isUpdatingFromProps.value = false
    })
  }
  // 监听 modelValue 变化
  watch(
    () => props.modelValue,
    (val) => {
      fillValue(val)
    },
    { immediate: true },
  )

  // 监听 accept 变化
  watch(
    () => props.accept,
    () => {
      fillAccept()
    },
    { immediate: true },
  )

  // 监听 fileList 变化
  watch(
    fileList,
    (val) => {
      // 只有当不是从 props 更新时才触发回调
      if (!isUpdatingFromProps.value) {
        successBack(val)
      }
    },
    { deep: true },
  )

  // 上传成功回调
  const successBack = (data: UploadFile[]) => {
    let res: string | UploadFile[]

    // 单文件返回URL
    if (!props.limit || props.limit === 1) {
      res = data.length > 0 && data[0].url ? data[0].url : ''
    } else {
      res = data
    }

    emit('update:modelValue', res)
  }

  // 上传的文件
  const fileSelected = (file: UploadFile | UploadRawFile) => {
    emit('select', file)
  }

  // 生命周期
  onMounted(() => {
    fillValue(props.modelValue)
  })
</script>

<style scoped>
  :deep(.el-upload-list--picture-card .el-upload-list__item) {
    overflow: hidden;
    background-color: #969696;
    border: 1px solid #c0ccda;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 80px;
    height: 80px;
    margin: 0 8px 8px 0;
    display: inline-block;
  }

  :deep(.el-upload--picture-card) {
    background-color: #fbfdff;
    border: 1px dashed #c0ccda;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 80px;
    height: 80px;
    cursor: pointer;
    line-height: 90px;
    vertical-align: top;
  }
</style>
